package com.weimob.mcloud.wechatwork.customer.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.OrgDepartmentUserExport;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.dto.data.EmployeeBO;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.dto.data.OrgDepartmentBO;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.dto.req.EmployeeDTO;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.dto.res.vid.RoleVidMemberResp;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.dto.res.vid.RoleVidResp;
import com.weimob.mcloud.wechatwork.common.utils.CollUtils;
import com.weimob.mcloud.wechatwork.common.utils.JsonUtil;
import com.weimob.mcloud.wechatwork.core.adapter.enums.uc.UCSourceTypeEnum;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.model.NodeInfo;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.request.NodeBaseInfoQueryDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.response.NodeInfoQueryBO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.request.customer.CDPUserConsumptionDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.response.customer.CDPUserConsumptionBO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.onecrm.request.BatchAccountGetDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.onecrm.response.AccountGetBO;
import com.weimob.mcloud.wechatwork.core.adapter.service.BosAdapterService;
import com.weimob.mcloud.wechatwork.core.adapter.service.OneCrmAdapterService;
import com.weimob.mcloud.wechatwork.core.adapter.service.cdp.CdpUserAdapterService;
import com.weimob.mcloud.wechatwork.core.base.MultiResponse;
import com.weimob.mcloud.wechatwork.core.base.SingleResponse;
import com.weimob.mcloud.wechatwork.core.constant.CustomerGroupConstant;
import com.weimob.mcloud.wechatwork.core.entity.base.Person;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.Customer;
import com.weimob.mcloud.wechatwork.core.entity.relation.employee.Employee;
import com.weimob.mcloud.wechatwork.core.entity.relation.group.CustomerGroup;
import com.weimob.mcloud.wechatwork.core.entity.relation.group.CustomerGroupExternal;
import com.weimob.mcloud.wechatwork.core.entity.relation.group.CustomerGroupMember;
import com.weimob.mcloud.wechatwork.core.enums.customer.CustomerStatusEnum;
import com.weimob.mcloud.wechatwork.core.enums.customer.ExternalUserTypeEnum;
import com.weimob.mcloud.wechatwork.core.enums.customer.GenderEnum;
import com.weimob.mcloud.wechatwork.core.enums.employee.EmployeeStatusEnum;
import com.weimob.mcloud.wechatwork.core.enums.group.*;
import com.weimob.mcloud.wechatwork.core.service.group.request.CustomerGroupExternalRequest;
import com.weimob.mcloud.wechatwork.core.service.group.request.CustomerGroupNonFriendResponse;
import com.weimob.mcloud.wechatwork.core.service.group.response.CustomerGroupNonFriendRequest;
import com.weimob.mcloud.wechatwork.customer.constant.RedisLockConstant;
import com.weimob.mcloud.wechatwork.customer.enums.UserPermissionRoleEnum;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.usermanagement.EmployeeProxy;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.usermanagement.UserPermissionProxy;
import com.weimob.mcloud.wechatwork.customer.facade.impl.customer.CustomerFacade;
import com.weimob.mcloud.wechatwork.customer.service.GroupService;
import com.weimob.mcloud.wechatwork.customer.service.impl.convert.CustomerGroupConvert;
import com.weimob.mcloud.wechatwork.customer.service.model.GenderStatisticModel;
import com.weimob.mcloud.wechatwork.customer.service.model.GroupStatisticModel;
import com.weimob.mcloud.wechatwork.customer.service.user.base.BasicInfo;
import com.weimob.mcloud.wechatwork.customer.service.user.base.PageResponse;
import com.weimob.mcloud.wechatwork.customer.service.user.exception.BaseErrorCode;
import com.weimob.mcloud.wechatwork.customer.service.user.exception.BizException;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.customer.ExternalUserListBO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.group.*;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.group.*;
import com.weimob.mcloud.wechatwork.customer.service.user.module.model.group.SimpleCustomerModel;
import com.weimob.mcloud.wechatwork.customer.service.user.module.model.group.SimpleEmployeeModel;
import com.weimob.mcloud.wechatwork.customer.service.user.module.model.group.SimpleGroupMemberModel;
import com.weimob.mcloud.wechatwork.customer.service.user.module.model.group.SimpleGroupModel;
import com.weimob.mcloud.wechatwork.customer.service.user.utils.SoaResponseUtil;
import com.weimob.mcloud.wechatwork.customer.third.NewRemoteOutServiceProxy;
import com.weimob.mcloud.wechatwork.customer.third.PicServerProxy;
import com.weimob.mcloud.wechatwork.customer.third.PrivateSphereThird;
import com.weimob.mcloud.wechatwork.customer.third.core.CustomerGroupExportServiceProxy;
import com.weimob.mcloud.wechatwork.customer.third.core.CustomerServiceProxy;
import com.weimob.mcloud.wechatwork.customer.utils.EasyExcelUtils;
import com.weimob.mcloud.wechatwork.statistics.service.CustomerGroupOverviewCurrentStatisticExport;
import com.weimob.mengdian.pic.sdk.model.UploadRes;
import com.weimob.soa.common.utils.SoaUtil;
import com.weimob.wechatwork.wechatworkexporter.ExportService;
import com.weimob.wechatwork.wechatworkexporter.enums.ExportTaskTypeEnum;
import com.weimob.wechatwork.wechatworkexporter.req.ExportTaskSaveDTO;
import com.weimob.wechatwork.wechatworkexporter.vo.ExportTaskSaveVo;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author liuzhu.chen
 * @date 2021/10/25
 */
@Service
@Slf4j
public class GroupServiceImpl implements GroupService {

    @Autowired
    private NewRemoteOutServiceProxy remoteOutServiceProxy;

    @Autowired
    PicServerProxy picServerProxy;

    @Reference
    BosAdapterService bosAdapterService;

    @Reference
    CustomerGroupOverviewCurrentStatisticExport currentStatisticExport;

    @Reference
    private ExportService exportService;

    @Reference
    CdpUserAdapterService cdpUserAdapterService;

    @Reference
    OneCrmAdapterService oneCrmAdapterService;

    @Reference
    private OrgDepartmentUserExport orgDepartmentUserExport;

    @Autowired
    private UserPermissionProxy userPermissionProxy;

    @Resource
    CustomerGroupExportServiceProxy customerGroupExportServiceProxy;

    @Value("${customer.query.max.size:100}")
    Integer partitionSize;

    @Autowired
    @Qualifier("customerGroupQueryThreadPool")
    private ThreadPoolTaskExecutor customerGroupQueryThreadPool;

    @Resource
    EmployeeProxy employeeProxy;

    @Resource
    CustomerServiceProxy customerServiceProxy;

    @Resource
    PrivateSphereThird privateSphereThird;

    @Resource
    private CustomerFacade customerFacade;
    /**
     * 企微助手产品id
     */
    @Value("${aewc.productId:203}")
    private Long aewcProductId;

    @Resource
    RedisTemplate<String, String> redisTemplate;

    @Override
    public PageResponse<CorpChatGroupListBO> listGroupJoinStore(@NonNull CorpChatGroupQueryDTO dto) {
        // 1、数据校验
        // 获取corpId
        if (Objects.isNull(dto.getBasicInfo())) {
            throw new BizException(BaseErrorCode.FETCH_CORP_ID_ERROR);
        }
        // 分页信息校验
        if (Objects.isNull(dto.getPageNum()) || Objects.isNull(dto.getPageSize())) {
            throw new BizException(BaseErrorCode.GROUP_PAGE_INFO_ERROR);
        }

        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), false);
        String corpId = privateSphere.getCorpId();

        if (StringUtils.isBlank(corpId)) {
            throw new BizException(BaseErrorCode.FETCH_CORP_ID_ERROR);
        }

        // 数据隔离权限判断
        String employeeId = "";
        List<Long> vidList = new ArrayList<>();
        // B端请求进行数据隔离逻辑端判断
        if (dto.getFromBrowser()) {
            if (Objects.nonNull(dto.getWid())) {
                RoleVidResp roleVidResp = userPermissionProxy.getRoleVid(privateSphere, null, dto.getWid());
                if (Objects.nonNull(roleVidResp) && Objects.nonNull(roleVidResp.getWidRole())) {
                    RoleVidMemberResp widRole = roleVidResp.getWidRole();
                    // 超级管理员查看所有数据-无需处理
                    // 普通管理员查看managerVidList下数据
                    if (UserPermissionRoleEnum.MANAGER.getRoleType().equals(widRole.getRoleType())) {
                        vidList = widRole.getVidList();
                    }
                    // 普通员工查看自己为群主的群数据
                    if (UserPermissionRoleEnum.EMPLOYEE.getRoleType().equals(widRole.getRoleType())) {
                        employeeId = widRole.getEmployeeId();
                    }
                } else {
                    throw new BizException(BaseErrorCode.NO_ROLE_INFO_ERROR);
                }
            } else {
                throw new BizException(BaseErrorCode.WID_IS_NULL_ERROR);
            }
        }
        List<String> ownerIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(dto.getOwnerIdList())) {
            ownerIdList.addAll(dto.getOwnerIdList());
        }
        if (StringUtils.isNotBlank(employeeId)) {
            ownerIdList.add(employeeId);
        }

        // 2、查询客户群数据
        CustomerGroup customerGroup = new CustomerGroup();
        customerGroup.setName(dto.getName());
        customerGroup.setPrivateSphere(privateSphere);
        Person owner = new Person();
        owner.setId(dto.getOwner());
        customerGroup.setOwner(owner);
        customerGroup.setGroupId(dto.getChatId());
        customerGroup.setState(ChatGroupStateEnum.getEnumByCode(dto.getState()));
        if (StringUtils.isNotBlank(dto.getRetailStoreId())) {
            CustomerGroupExternal customerGroupExternal = new CustomerGroupExternal();
            customerGroupExternal.setExternalType(ChatGroupExternalTypeEnum.NEW);
            customerGroupExternal.setVid(dto.getRetailStoreId());
            customerGroup.setExternal(customerGroupExternal);
        }
        customerGroup.setAuthorizationStatus(GroupAuthorizationStatusEnum.getEnumByCode(dto.getAuthorizationStatus()));
        // 普通管理员vidList过滤
        customerGroup.setManagedVid(vidList);
        HashMap<String, Object> extInfo = new HashMap<>();
        extInfo.put("orderBy", "groupCreateTime");
        extInfo.put("direction", "desc");
        MultiResponse<CustomerGroup> multiResponse = customerGroupExportServiceProxy.fetchCustomerGroupListES(customerGroup, true, false, dto.getPageNum(), dto.getPageSize(),
                extInfo, ownerIdList, dto.getChatIdList(), dto.getCreateTimeStart(), dto.getCreateTimeEnd(),true);
        List<CustomerGroup> dataList = multiResponse.getDataList();

        // 3、查询门店信息
        List<Long> storeVids = new ArrayList<>();
        List<String> groupIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(dataList)) {
            for (CustomerGroup group : dataList) {
                if (Objects.nonNull(group.getExternal())) {
                    storeVids.add(Long.parseLong(group.getExternal().getVid()));
                }
                groupIdList.add(group.getGroupId());
            }
        }
        Map<String, NodeInfo> nodeInfoMap = null;
        if (!CollectionUtils.isEmpty(storeVids)) {
            NodeBaseInfoQueryDTO nodeBaseInfoQueryDTO = new NodeBaseInfoQueryDTO();
            nodeBaseInfoQueryDTO.setMerchantId(dto.getBasicInfo().getMerchantId());
            nodeBaseInfoQueryDTO.setBosId(dto.getBasicInfo().getBosId());
            nodeBaseInfoQueryDTO.setVids(storeVids);
            List<NodeInfoQueryBO> nodeInfoQueryBOS = SoaUtil.unpack(bosAdapterService.queryNodeBaseInfoByVidOrName(nodeBaseInfoQueryDTO));
            nodeInfoMap = nodeInfoQueryBOS.stream().map(NodeInfoQueryBO::getNodeInfo).collect(Collectors.toMap(NodeInfo::getVidCode, Function.identity(), (k1, k2) -> k1));
        }

        // 4、查询群实时统计信息
        Map<String, GroupStatisticModel> statisticModelMap = getStatisticModelMap(privateSphere, groupIdList, Boolean.TRUE.equals(dto.getIsExport()));

        // 5、查询群主所属部门
        Map<String, EmployeeBO> ownerIdEmployeeMap = new HashMap<>();
        if (dto.getIsExport() && !CollectionUtils.isEmpty(dataList)) {
            Set<String> employeeIds = dataList.stream().filter(e -> Objects.nonNull(e.getOwner()) && Objects.nonNull(e.getOwner().getId())).map(e -> e.getOwner().getId()).collect(Collectors.toSet());
            ownerIdEmployeeMap = getStringEmployeeBOMap(privateSphere, Lists.newArrayList(employeeIds));
        }

        // 6、结果封装
        List<CorpChatGroupListBO> resultList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(dataList)) {
            for (CustomerGroup group : dataList) {
                CorpChatGroupListBO bo = new CorpChatGroupListBO();
                bo.setName(group.getName());
                Employee employee = (Employee) group.getOwner();
                if (Objects.nonNull(employee)) {
                    bo.setOwner(employee.getId());
                    bo.setOwnerName(employee.getName());
                    bo.setHaveBindGuide(!CollectionUtils.isEmpty(employee.getGuiderList()));
                    if (Objects.nonNull(employee.getStatus())) {
                        bo.setOwnerStatus(employee.getStatus().getCode());
                    }
                    if (StringUtils.isBlank(group.getName()) && StringUtils.isNotBlank(employee.getName())) {
                        bo.setName(String.format("%s的群（未命名）", employee.getName()));
                    }
                }
                // 门店信息
                if (Objects.nonNull(group.getExternal()) && Objects.nonNull(nodeInfoMap) && !nodeInfoMap.isEmpty()) {
                    if (Objects.nonNull(nodeInfoMap.get(group.getExternal().getVid()))) {
                        bo.setRetailStoreName(nodeInfoMap.get(group.getExternal().getVid()).getVidName());
                        bo.setRetailStoreId(nodeInfoMap.get(group.getExternal().getVid()).getVidCode());
                    }
                }
                // 统计信息
                GroupStatisticModel model = statisticModelMap.get(group.getGroupId());
                if (Objects.nonNull(model)) {
                    bo.setJoinNum(model.getJoinNum());
                    bo.setQuitNum(model.getQuitNum());
                    bo.setNoFriendNum(model.getNoFriendNum());
                } else {
                    bo.setJoinNum(0);
                    bo.setQuitNum(0);
                    bo.setNoFriendNum(0);
                }
                bo.setNum(group.getNum());
                bo.setCustomerNum(group.getExternalUserNum());
                bo.setGroupCreateTime(group.getCreateTime());
                bo.setState(group.getState().getCode());
                bo.setChatId(group.getGroupId());
                bo.setNotice(group.getNotice());

                if (Objects.nonNull(group.getAuthorizationStatus())) {
                    if (group.getAuthorizationStatus().getCode() == 1) {
                        bo.setName(String.format("%s（已失效）", bo.getName()));
                        bo.setState(2);
                    }
                    bo.setAuthorizationStatus(group.getAuthorizationStatus().getCode());
                }
                // 群主所属部门
                if (MapUtils.isNotEmpty(ownerIdEmployeeMap) && Objects.nonNull(ownerIdEmployeeMap.get(group.getOwnerId()))) {
                    EmployeeBO employeeBO = ownerIdEmployeeMap.get(group.getOwnerId());
                    String departmentName = this.jointDepartmentName(employeeBO.getOrgDepartmentListBOs()).stream().collect(Collectors.joining("、"));
                    bo.setDepartment(departmentName);
                }
                resultList.add(bo);
            }
        }

        PageResponse<CorpChatGroupListBO> pagination = new PageResponse<CorpChatGroupListBO>();
        pagination.setResults(resultList);
        pagination.setPageNum(dto.getPageNum());
        pagination.setPageSize(dto.getPageSize());
        pagination.setTotalPage(multiResponse.getTotalPage());
        pagination.setTotalCount(multiResponse.getTotalCount());
        return pagination;
    }

    /**
     * 获取客户群统计信息
     *
     * @param groupIdList     groupIdList
     * @param needNoFriendNum boolean
     * @return map
     */
    private Map<String, GroupStatisticModel> getStatisticModelMap(PrivateSphere privateSphere, List<String> groupIdList, boolean needNoFriendNum) {
        Map<String, GroupStatisticModel> statisticModelMap = new HashMap<>(16);
        List<GroupStatisticModel> statisticModelList = new ArrayList<>();
        if (CollectionUtils.isEmpty(groupIdList)) {
            return statisticModelMap;
        }
        // 进群客户数
        String joinKey = String.format(RedisLockConstant.CUSTOMER_GROUP_JOIN_STATISTIC_BOS, privateSphere.getBosId());
        HashOperations<String, String, Long> hashOperations = redisTemplate.opsForHash();
        List<Long> joinNumList = hashOperations.multiGet(joinKey, groupIdList);

        // 退群客户数
        String quitKey = String.format(RedisLockConstant.CUSTOMER_GROUP_QUIT_STATISTIC_BOS, privateSphere.getBosId());
        List<Long> quitNumList = hashOperations.multiGet(quitKey, groupIdList);

        // 非企业好友数
        Map<String, Integer> nonFriendMap = new HashMap<>();
        if (needNoFriendNum) {
            CustomerGroupNonFriendRequest nonFriendRequest = new CustomerGroupNonFriendRequest();
            nonFriendRequest.setCorpId(privateSphere.getCorpId());
            nonFriendRequest.setPrivateSphere(privateSphere);
            nonFriendRequest.setGroupIdList(groupIdList);
            MultiResponse<CustomerGroupNonFriendResponse> nonFriendMultiResponse = customerGroupExportServiceProxy.batchFetchNonFriendNum(nonFriendRequest);
            List<CustomerGroupNonFriendResponse> nonFriendDataList = nonFriendMultiResponse.getDataList();
            if (CollectionUtils.isNotEmpty(nonFriendDataList)) {
                nonFriendMap = nonFriendDataList.stream().collect(Collectors.toMap(CustomerGroupNonFriendResponse::getGroupId, CustomerGroupNonFriendResponse::getNoFriendNum, (k1, k2) -> k1));
            }
        }

        for (int i = 0; i < groupIdList.size(); i++) {
            GroupStatisticModel model = new GroupStatisticModel();
            model.setGroupId(groupIdList.get(i));
            if (CollectionUtils.isNotEmpty(joinNumList) && Objects.nonNull(joinNumList.get(i))) {
                model.setJoinNum(Integer.parseInt(String.valueOf(joinNumList.get(i))));
            } else {
                model.setJoinNum(0);
            }
            if (CollectionUtils.isNotEmpty(quitNumList) && Objects.nonNull(quitNumList.get(i))) {
                model.setQuitNum(Integer.parseInt(String.valueOf(quitNumList.get(i))));
            } else {
                model.setQuitNum(0);
            }
            if (MapUtils.isNotEmpty(nonFriendMap) && Objects.nonNull(nonFriendMap.get(groupIdList.get(i)))) {
                model.setNoFriendNum(nonFriendMap.get(groupIdList.get(i)));
            } else {
                model.setNoFriendNum(0);
            }
            statisticModelList.add(model);
        }
        statisticModelMap = statisticModelList.stream().collect(Collectors.toMap(GroupStatisticModel::getGroupId, Function.identity(), (k1, k2) -> k1));
        return statisticModelMap;
    }


    @Override
    public PageResponse<CorpChatGroupMemberBO> memberList(@NonNull CustomerGroupMemberQueryDTO dto) {
        // 是否折叠查询
        Boolean collapseQuery = dto.getCollapseQuery();

        // 1、查私域信息
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), false);

        // 2、分页查询客户群成员
        CustomerGroupMember customerGroupMember = new CustomerGroupMember();
        customerGroupMember.setPrivateSphere(privateSphere);
        customerGroupMember.setGroupId(dto.getChatId());
        customerGroupMember.setNickname(dto.getMemberName());
        if (Objects.nonNull(dto.getMemberType())) {
            customerGroupMember.setGroupMemberType(GroupMemberTypeEnum.getEnumByCode(dto.getMemberType()));
        }
        if (Objects.nonNull(dto.getEmployeeId())) {
            Employee invitor = new Employee();
            invitor.setId(dto.getEmployeeId());
            customerGroupMember.setInvitor(invitor);
        }
        customerGroupMember.setIsFriend(dto.getIsFriend());
        Map<String, Object> extInfo = new HashMap();
        extInfo.put("collapseQuery", collapseQuery);
        extInfo.put(CustomerGroupConstant.FETCH_GUIDER, Boolean.TRUE);
        MultiResponse<CustomerGroupMember> multiResponse = customerGroupExportServiceProxy.fetchCustomerGroupMemberListES(customerGroupMember, extInfo, true,
                true, dto.getPageNum(), dto.getPageSize());
        List<CustomerGroupMember> dataList = multiResponse.getDataList();


        // 3、查询群基本信息
        CustomerGroup customerGroup = null;
        // 折叠查询-不需要查询群信息
        if (Boolean.FALSE.equals(collapseQuery)) {
            CustomerGroup customerGroupQuery = new CustomerGroup();
            customerGroupQuery.setPrivateSphere(privateSphere);
            customerGroupQuery.setGroupId(dto.getChatId());
            MultiResponse<CustomerGroup> groupMultiResponse = customerGroupExportServiceProxy.fetchCustomerGroupList(customerGroupQuery, null, null,
                    null, false, false, null, null, true);
            if (!CollectionUtils.isEmpty(groupMultiResponse.getDataList())) {
                customerGroup = groupMultiResponse.getDataList().get(0);
            }
        }

        // 4、批量查询消费总金额
        Map<String, Long> memberIdWidMap = new HashMap<>();
        Map<String, BigDecimal> widAmountMap = new HashMap<>();
        List<Long> widList = new ArrayList<>();
        List<String> memberIdList = dataList.stream().filter(e -> e.getGroupMemberType() == GroupMemberTypeEnum.EXTERNAL_USER).map(CustomerGroupMember::getMemberId).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(memberIdList)) {

            // 批量换取wid
            List<AccountGetBO> accountGetBOList = new ArrayList<>();
            List<List<String>> partition = Lists.partition(memberIdList, 10);
            for (List<String> memberIds : partition) {
                BatchAccountGetDTO accountGetDTO = new BatchAccountGetDTO();
                accountGetDTO.setBosId(privateSphere.getBosId());
                accountGetDTO.setUcSourceTypeEnum(UCSourceTypeEnum.WORK_WEIXIN_EXTERNAL_USERID);
                accountGetDTO.setOpenIdList(memberIds);
                accountGetDTO.setAppId(privateSphere.getCorpId());
                // 接口限制10，passport后期优化
                List<AccountGetBO> accountGetBOs = SoaResponseUtil.unpack(oneCrmAdapterService.batchGetAccountByOpenIds(accountGetDTO));
                if (!CollectionUtils.isEmpty(accountGetBOs)) {
                    accountGetBOList.addAll(accountGetBOs);
                }
            }
            // 过滤下返回wid或externalUserId为空的数据
            if (!CollectionUtils.isEmpty(accountGetBOList)) {
                List<AccountGetBO> collect = accountGetBOList.stream().filter(e -> Objects.nonNull(e.getWid()) && Objects.nonNull(e.getOpenId())).collect(Collectors.toList());
                widList = collect.stream().map(AccountGetBO::getWid).collect(Collectors.toList());
                memberIdWidMap = collect.stream().collect(Collectors.toMap(AccountGetBO::getOpenId, AccountGetBO::getWid, (k1, k2) -> k1));
            }

            // 批量查询消费记录
            if (!CollectionUtils.isEmpty(widList) && !collapseQuery) {
                // 批量查询消费记录
                CDPUserConsumptionDTO cdpUserConsumeGetDTO = new CDPUserConsumptionDTO();
                cdpUserConsumeGetDTO.setBosId(privateSphere.getBosId());
                List<String> strWidList = widList.stream().map(e -> String.valueOf(e)).collect(Collectors.toList());
                cdpUserConsumeGetDTO.setWidList(strWidList);
                // 接口限制200
                List<CDPUserConsumptionBO> userConsumptionBOList = SoaResponseUtil.unpack(cdpUserAdapterService.getCDPUserConsumptionList(cdpUserConsumeGetDTO));
                if (!CollectionUtils.isEmpty(userConsumptionBOList)) {
                    widAmountMap = userConsumptionBOList.stream().filter(e -> Objects.nonNull(e.getTotalConsumeAmount()) && Objects.nonNull(e.getWid()))
                            .collect(Collectors.toMap(CDPUserConsumptionBO::getWid,
                                    CDPUserConsumptionBO::getTotalConsumeAmount, (k1, k2) -> k1));
                }
            }
        }

        // 5、查邀请员工部门信息
        Map<String, EmployeeBO> invitorIdEmployeeMap = new HashMap<>();
        if (dto.getIsExport() && !CollectionUtils.isEmpty(dataList)) {
            Set<String> employeeIds = dataList.stream().filter(e -> Objects.nonNull(e.getInvitor())).map(e -> e.getInvitor().getId()).collect(Collectors.toSet());
            invitorIdEmployeeMap = getStringEmployeeBOMap(privateSphere, Lists.newArrayList(employeeIds));
        }

        // 6、模型转换
        List<CorpChatGroupMemberBO> resultList = new ArrayList<>(dataList.size());
        for (CustomerGroupMember groupMember : dataList) {
            CorpChatGroupMemberBO bo = new CorpChatGroupMemberBO();
            if (GroupMemberTypeEnum.EMPLOYEE == groupMember.getGroupMemberType() && !Objects.isNull(groupMember.getEmployee())) {
                // 员工
                Employee employee = groupMember.getEmployee();
                bo.setMemberId(employee.getId());
                if (EmployeeStatusEnum.DISABLED == employee.getStatus()) {
                    bo.setName(employee.getName() + "（已禁用）");
                } else {
                    bo.setName(employee.getName());
                }
                bo.setType(1);
                bo.setDetailFlag(false);
                if (Objects.nonNull(employee.getStatus())) {
                    bo.setUserStatus(employee.getStatus().getCode());
                }
                bo.setHaveBindGuide(!CollectionUtils.isEmpty(employee.getGuiderList()));
                bo.setProfilePicture(employee.getAvatar());
            } else if (GroupMemberTypeEnum.EXTERNAL_USER == groupMember.getGroupMemberType() && !Objects.isNull(groupMember.getCustomer())) {
                // 客户
                Customer customer = groupMember.getCustomer();
                bo.setMemberId(customer.getId());
                bo.setExternalUserId(customer.getExternalUserid());
                bo.setName(customer.getName());
                bo.setType(2);
                if (StringUtils.isNotBlank(bo.getName()) && CustomerStatusEnum.DEFAULT.equals(customer.getStatus())) {
                    bo.setDetailFlag(true);
                } else {
                    bo.setDetailFlag(false);
                }
                bo.setExternalUserSource(Objects.isNull(customer.getExternalUserType()) ? 3 : customer.getExternalUserType().getCode());
                bo.setCompanyName(customer.getCorpFullName());
                if (Objects.nonNull(groupMember.getIsFriend())) {
                    bo.setHaveFriend(groupMember.getIsFriend() == 1);
                } else {
                    bo.setHaveFriend(false);
                }
                bo.setProfilePicture(customer.getAvatar());
                // 总消费金额
                if (MapUtils.isNotEmpty(memberIdWidMap) && Objects.nonNull(memberIdWidMap.get(customer.getExternalUserid()))) {
                    Long wid = memberIdWidMap.get(customer.getExternalUserid());
                    bo.setSuperWid(wid);
                    if (MapUtils.isNotEmpty(widAmountMap) && Objects.nonNull(widAmountMap.get(String.valueOf(wid)))) {
                        bo.setConsumeAmount(widAmountMap.get(String.valueOf(wid)));
                    }
                }
                bo.setUnionid(customer.getUnionid());
            }

            if (StringUtils.isEmpty(bo.getName())) {
                bo.setName(groupMember.getNickname());
            }

            // joinScene 莫名奇妙为0,没有对应的入群方式,怀疑是腾讯的bug,兼容下
            if (Objects.isNull(groupMember.getJoinScene())) {
                bo.setJoinScene(JoinSceneEnum.DIRECT.getCode());
                bo.setJoinSceneDesc(JoinSceneEnum.DIRECT.getDesc());
            } else {
                bo.setJoinSceneDesc(groupMember.getJoinScene().getDesc());
                bo.setJoinScene(groupMember.getJoinScene().getCode());
            }
            // 群主建群
            if (Objects.nonNull(customerGroup) && Objects.nonNull(groupMember.getMemberId()) && groupMember.getMemberId().equals(customerGroup.getOwner().getId())) {
                bo.setJoinScene(JoinSceneEnum.OWNER.getCode());
                bo.setJoinSceneDesc(JoinSceneEnum.OWNER.getDesc());
                bo.setIsOwner(true);
            }
            bo.setJoinTime(groupMember.getJoinTime());
            // 邀请员工
            Employee invitor = groupMember.getInvitor();
            if (Objects.nonNull(invitor)) {
                bo.setInviteName(invitor.getName());
                bo.setInviteEmployeeId(invitor.getId());
                if (MapUtils.isNotEmpty(invitorIdEmployeeMap) && Objects.nonNull(invitorIdEmployeeMap.get(invitor.getId()))) {
                    EmployeeBO employeeBO = invitorIdEmployeeMap.get(invitor.getId());
                    String departmentName = this.jointDepartmentName(employeeBO.getOrgDepartmentListBOs()).stream().collect(Collectors.joining("、"));
                    bo.setDepartment(departmentName);
                }

            }
            resultList.add(bo);
        }

        // 7、封装结果
        PageResponse<CorpChatGroupMemberBO> pagination = new PageResponse<>();
        pagination.setResults(resultList);
        pagination.setPageNum(dto.getPageNum());
        pagination.setPageSize(dto.getPageSize());
        pagination.setTotalPage(multiResponse.getTotalPage());
        pagination.setTotalCount(multiResponse.getTotalCount());
        return pagination;
    }

    @Override
    public Boolean memberExport(CustomerGroupMemberQueryDTO dto) {
        // 1、数据校验
        if (Objects.isNull(dto.getBasicInfo())) {
            throw new BizException("basicInfo 不能为空");
        }
        if (Objects.isNull(dto.getChatId())) {
            throw new BizException("chatId 不能为空");
        }

        // 2、查私域
        PrivateSphere privateSphereResult = privateSphereThird.fetch(dto.getBasicInfo(), false);

        // 3、查询客户群名称
        CustomerGroup customerGroupQuery = new CustomerGroup();
        customerGroupQuery.setPrivateSphere(privateSphereResult);
        customerGroupQuery.setGroupId(dto.getChatId());
        MultiResponse<CustomerGroup> multiResponse = customerGroupExportServiceProxy.fetchCustomerGroupList(customerGroupQuery, null, null,
                null, false, false, null, null,true);
        CustomerGroup customerGroup = multiResponse.getDataList().get(0);
        String groupName = "";
        if (Objects.nonNull(customerGroup)) {
            Employee owner = (Employee) customerGroup.getOwner();
            groupName = customerGroup.getName();
            if (StringUtils.isEmpty(groupName) && Objects.nonNull(owner)) {
                groupName = String.format("%s的群（未命名）", owner.getName());
            }
        }

        // 4、创建导出任务
        ExportTaskSaveDTO exportTaskSaveDTO = new ExportTaskSaveDTO();
        exportTaskSaveDTO.setBosId(privateSphereResult.getBosId());
        exportTaskSaveDTO.setWid(dto.getWid());
        String dateStr = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now());
        exportTaskSaveDTO.setFileName(String.format("群客资导出-%s-%s", groupName, dateStr));
        exportTaskSaveDTO.setTaskType(ExportTaskTypeEnum.CUSTOMER_GROUP_MEMBER_INFO_DOWNLOAD.getType());
        exportTaskSaveDTO.setVid(dto.getBasicInfo().getVid());
        exportTaskSaveDTO.setProductId(privateSphereResult.getProductId());
        exportTaskSaveDTO.setParams(JsonUtil.obj2Str(dto));
        ExportTaskSaveVo unpack = SoaUtil.unpack(exportService.saveExportTask(exportTaskSaveDTO));
        log.info("群客资导出：{}", JSON.toJSONString(unpack));
        return Boolean.TRUE;
    }

    @Override
    public Boolean export(CorpChatGroupQueryDTO dto) {
        PrivateSphere privateSphereResult = privateSphereThird.fetch(dto.getBasicInfo(), false);
        // 创建导出任务
        ExportTaskSaveDTO exportTaskSaveDTO = new ExportTaskSaveDTO();
        exportTaskSaveDTO.setBosId(privateSphereResult.getBosId());
        exportTaskSaveDTO.setWid(dto.getWid());
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
        String nowStr = dtf.format(LocalDateTime.now());
        exportTaskSaveDTO.setFileName("客户群列表导出-" + nowStr);
        exportTaskSaveDTO.setTaskType(ExportTaskTypeEnum.CUSTOMER_GROUP_INFO_DOWNLOAD.getType());
        exportTaskSaveDTO.setVid(dto.getBasicInfo().getVid());
        exportTaskSaveDTO.setProductId(privateSphereResult.getProductId());
        exportTaskSaveDTO.setParams(JsonUtil.obj2Str(dto));
        ExportTaskSaveVo unpack = SoaUtil.unpack(exportService.saveExportTask(exportTaskSaveDTO));
        log.info("客户群列表数据导出：{}", JSON.toJSONString(unpack));
        return Boolean.TRUE;
    }

    /**
     * 客户群和门店关系导入
     *
     * @param dto
     * @return
     */
    @Override
    public RetailStoreExcelBO importExcel(RetailStoreExcelImportDTO dto) {
        // 私域
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), false);

        RetailStoreExcelBO retailStoreExcelBO = new RetailStoreExcelBO();
        List<RetailStoreExcelDTO> excelDTOS = getRetailStoreExcelDTOS(dto.getUrl());
        List<RetailStoreExcelDTO> tempDTOS = Lists.newArrayListWithCapacity(excelDTOS.size()); // 基础校验
        List<RetailStoreExcelDTO> checkSuccessExcelDTOS = Lists.newArrayListWithCapacity(excelDTOS.size()); // 校验成功数据
        List<RetailStoreExcelDTO> checkFailExcelDTOS = Lists.newArrayListWithCapacity(excelDTOS.size()); // 校验失败数据

        // 判空处理
        if (excelDTOS.isEmpty()) {
            retailStoreExcelBO.setTotalNum(0);
            retailStoreExcelBO.setSuccessNum(0);
            retailStoreExcelBO.setFailedNum(0);
            retailStoreExcelBO.setResult(false);
            return retailStoreExcelBO;
        }

        // Excel数据类型校验
        excelDTOS.forEach(e -> {
            if (StringUtils.isBlank(e.getRetailStoreName())) {
                e.setFailReason("未找到该零售门店，请前往零售店铺查看");
                checkFailExcelDTOS.add(e);
                return;
            }
            if (StringUtils.isBlank(e.getChatName())) {
                e.setFailReason("未找到该群聊名称，请先创建或命名该群聊");
                checkFailExcelDTOS.add(e);
                return;
            }
            tempDTOS.add(e);
        });

        // 初步校验全部不通过
        if (tempDTOS.isEmpty()) {
            // 失败行存入媒体中心
            if (!checkFailExcelDTOS.isEmpty()) {
                UploadRes uploadRes = uploadExcel(checkFailExcelDTOS);
                retailStoreExcelBO.setFailedExcelUrl(uploadRes.getUrl());
            }
            retailStoreExcelBO.setTotalNum(excelDTOS.size());
            retailStoreExcelBO.setSuccessNum(checkSuccessExcelDTOS.size());
            retailStoreExcelBO.setFailedNum(checkFailExcelDTOS.size());
            retailStoreExcelBO.setResult(false);
            return retailStoreExcelBO;
        }

        // 批量获取群信息
        List<String> groupNames = tempDTOS.stream().map(RetailStoreExcelDTO::getChatName).collect(Collectors.toList());
        CustomerGroup customerGroupQuery = new CustomerGroup();
        customerGroupQuery.setPrivateSphere(privateSphere);
        MultiResponse<CustomerGroup> multiResponse = customerGroupExportServiceProxy.fetchCustomerGroupList(customerGroupQuery, null,
                null, groupNames, false, false, null, null, false);
        List<CustomerGroup> dataList = multiResponse.getDataList();
        Map<String, List<CustomerGroup>> customerGroupMap = dataList.stream().collect(Collectors.groupingBy(CustomerGroup::getName));


        // 批量获取零售门店信息
        List<String> storeNameList = tempDTOS.stream().map(RetailStoreExcelDTO::getRetailStoreName).collect(Collectors.toList());
        NodeBaseInfoQueryDTO nodeBaseInfoQueryDTO = new NodeBaseInfoQueryDTO();
        nodeBaseInfoQueryDTO.setMerchantId(dto.getBasicInfo().getMerchantId());
        nodeBaseInfoQueryDTO.setBosId(dto.getBasicInfo().getBosId());
        nodeBaseInfoQueryDTO.setNodeNames(storeNameList);
        List<NodeInfoQueryBO> allStoreInfoList = SoaUtil.unpack(bosAdapterService.queryNodeBaseInfoByVidOrName(nodeBaseInfoQueryDTO));

        // 校验Excel
        Map<String, NodeInfoQueryBO> storeSimpleInfoVoMap = allStoreInfoList.stream().collect(Collectors.toMap(nodeInfoQueryBO -> nodeInfoQueryBO.getNodeInfo().getVidName(), Function.identity(), (k1, k2) -> k1));
        for (RetailStoreExcelDTO tempDTO : tempDTOS) {
            // 校验群信息（未命名、群解散、群名称不完全相同）
            List<CustomerGroup> groups = customerGroupMap.get(tempDTO.getChatName());
            if (CollectionUtils.isEmpty(groups)) {
                tempDTO.setFailReason("未找到该群聊名称，请先创建或命名该群聊");
                checkFailExcelDTOS.add(tempDTO);
                continue;
            } else {
                // 判断群全部解散
                boolean b = groups.stream().anyMatch(group -> ChatGroupStateEnum.GENERAL.equals(group.getState()));
                if (!b) {
                    tempDTO.setFailReason("未找到该群聊名称，请先创建或命名该群聊");
                    checkFailExcelDTOS.add(tempDTO);
                    continue;
                }
            }
            NodeInfoQueryBO infoVo = storeSimpleInfoVoMap.get(tempDTO.getRetailStoreName());
            if (infoVo == null) {
                tempDTO.setFailReason("未找到该零售门店，请前往零售店铺查看");
                checkFailExcelDTOS.add(tempDTO);
                continue;
            }
            checkSuccessExcelDTOS.add(tempDTO);
        }

        if (!checkFailExcelDTOS.isEmpty()) {
            UploadRes uploadRes = uploadExcel(checkFailExcelDTOS);
            retailStoreExcelBO.setFailedExcelUrl(uploadRes.getUrl());
        }

        // 将成功行落库
        if (!checkSuccessExcelDTOS.isEmpty()) {
            batchInsertGroupStoreRelate(checkSuccessExcelDTOS, customerGroupMap, storeSimpleInfoVoMap, privateSphere);
        }
        // 记录 总数 成功数 失败数
        retailStoreExcelBO.setTotalNum(excelDTOS.size());
        retailStoreExcelBO.setSuccessNum(checkSuccessExcelDTOS.size());
        retailStoreExcelBO.setFailedNum(checkFailExcelDTOS.size());
        retailStoreExcelBO.setResult(excelDTOS.size() == checkSuccessExcelDTOS.size());
        return retailStoreExcelBO;
    }

    /**
     * 查询客户群详情
     *
     * @param dto
     * @return
     */
    @Override
    public CorpChatGroupDetailBO queryDetail(CorpChatGroupDetailDTO dto) {
        // 1、查私域信息
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), false);

        // 2、查询群详情信息
        CustomerGroup customerGroupQuery = new CustomerGroup();
        customerGroupQuery.setGroupId(dto.getChatId());
        customerGroupQuery.setPrivateSphere(privateSphere);
        Map<String, Object> detailExtInfo = new HashMap();
        detailExtInfo.put(CustomerGroupConstant.FETCH_GUIDER,Boolean.TRUE);
        SingleResponse<CustomerGroup> singleResponse = customerGroupExportServiceProxy.fetchCustomerGroupDetail(customerGroupQuery,true, detailExtInfo);
        CustomerGroup customerGroup = singleResponse.getData();
        if (Objects.isNull(customerGroup)) {
            return null;
        }

        // 3、模型转换
        // 3.1、基本信息
        CorpChatGroupDetailBO corpChatGroupDetailBO = new CorpChatGroupDetailBO();
        corpChatGroupDetailBO.setChatId(customerGroup.getGroupId());
        corpChatGroupDetailBO.setExternalUserNum(customerGroup.getExternalUserNum());
        corpChatGroupDetailBO.setGroupCreateTime(customerGroup.getCreateTime());
        corpChatGroupDetailBO.setName(customerGroup.getName());
        if (Objects.nonNull(customerGroup.getOwner())) {
            Employee owner = (Employee) customerGroup.getOwner();
            if (StringUtils.isBlank(customerGroup.getName()) && StringUtils.isNotBlank(owner.getName())) {
                corpChatGroupDetailBO.setName(String.format("%s的群（未命名）", owner.getName()));
            }
            corpChatGroupDetailBO.setOwner(owner.getId());
            if (EmployeeStatusEnum.DISABLED == owner.getStatus()) {
                corpChatGroupDetailBO.setOwnerName(owner.getName() + "（已禁用）");
            } else {
                corpChatGroupDetailBO.setOwnerName(owner.getName());
            }
            corpChatGroupDetailBO.setHaveBindGuide(!CollectionUtils.isEmpty(owner.getGuiderList()));
        }
        corpChatGroupDetailBO.setNotice(customerGroup.getNotice());
        corpChatGroupDetailBO.setNum(customerGroup.getNum());
        corpChatGroupDetailBO.setState(customerGroup.getState().getCode());
        // 3.2、门店信息
        if (Objects.nonNull(customerGroup.getExternal())) {
            NodeBaseInfoQueryDTO nodeBaseInfoQueryDTO = new NodeBaseInfoQueryDTO();
            nodeBaseInfoQueryDTO.setMerchantId(dto.getBasicInfo().getMerchantId());
            nodeBaseInfoQueryDTO.setBosId(dto.getBasicInfo().getBosId());
            long vid = Long.parseLong(customerGroup.getExternal().getVid());
            nodeBaseInfoQueryDTO.setVids(Lists.newArrayList(vid));
            List<NodeInfoQueryBO> nodeInfoQueryBOList = SoaUtil.unpack(bosAdapterService.queryNodeBaseInfoByVidOrName(nodeBaseInfoQueryDTO));
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(nodeInfoQueryBOList) && nodeInfoQueryBOList.get(0).getNodeInfo() != null) {
                corpChatGroupDetailBO.setRetailStoreName(nodeInfoQueryBOList.get(0).getNodeInfo().getVidName());
            }
        }

        // 3.3、性别统计
        // 查群成员信息
        CustomerGroupMember customerGroupMemberReq = new CustomerGroupMember();
        customerGroupMemberReq.setPrivateSphere(privateSphere);
        customerGroupMemberReq.setGroupId(dto.getChatId());
        Map<String, Object> extInfo = new HashMap();
        extInfo.put(CustomerGroupConstant.FETCH_GUIDER,Boolean.TRUE);
        MultiResponse<CustomerGroupMember> memberMultiResponse = customerGroupExportServiceProxy.fetchCustomerGroupMemberList(customerGroupMemberReq, extInfo,
                false, false, null, null);

        // 按照成员类型分组
        if (Objects.nonNull(memberMultiResponse) && !CollectionUtils.isEmpty(memberMultiResponse.getDataList())) {
            List<CustomerGroupMember> memberList = memberMultiResponse.getDataList();
            // 异步分批获取员工&客户信息
            List<Future<List<Customer>>> customerFutureList = new ArrayList<>();
            List<Future<List<Employee>>> employeeFutureList = new ArrayList<>();
            fillFutureList(customerFutureList, employeeFutureList, privateSphere, memberList);

            // 性别分布统计
            GenderStatisticModel genderStatisticModel = new GenderStatisticModel(0, 0, 0);
            getGenderStatisticModel(customerFutureList, employeeFutureList, genderStatisticModel, memberList);

            corpChatGroupDetailBO.setMaleNum(genderStatisticModel.getMaleNum());
            corpChatGroupDetailBO.setFemaleNum(genderStatisticModel.getFemaleNum());
            corpChatGroupDetailBO.setUnknownNum(genderStatisticModel.getUnknownNum());
        }

        // 4、返回结果
        return corpChatGroupDetailBO;
    }

    @Override
    public SimpleGroupModel fetchGroupWithRichMember(SimpleGroupQueryDTO simpleGroupQueryDTO) {
        SimpleGroupModel resultSimpleGroupModel = new SimpleGroupModel();
        BasicInfo basicInfo = simpleGroupQueryDTO.getBasicInfo();
        String chatId = simpleGroupQueryDTO.getChatId();

        // 1、校验
        if (StringUtils.isBlank(chatId)) {
            throw new BizException("GroupServiceImpl.fetchGroupWithRichMember 参数异常");
        }
        PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, true);

        // 2、获取群信息（携带"充血"群成员）
        CustomerGroup groupWithRichMember = getGroupWithRichMember(chatId, privateSphere);
        if (Objects.isNull(groupWithRichMember)) {
            return null;
        }

        // 3、模型转换
        resultSimpleGroupModel.setCorpId(groupWithRichMember.getCorpId());
        resultSimpleGroupModel.setChatId(groupWithRichMember.getGroupId());
        resultSimpleGroupModel.setName(groupWithRichMember.getName());
        // 群
        if (Objects.nonNull(groupWithRichMember.getOwner())) {
            Employee employee = (Employee) groupWithRichMember.getOwner();
            SimpleEmployeeModel owner = getEmployeeModel(employee);
            resultSimpleGroupModel.setOwner(owner);
        }
        resultSimpleGroupModel.setGroupCreateTime(groupWithRichMember.getCreateTime());
        resultSimpleGroupModel.setGroupState(groupWithRichMember.getStateCode());
        resultSimpleGroupModel.setNotice(groupWithRichMember.getNotice());
        resultSimpleGroupModel.setAuthorizationStatus(groupWithRichMember.getAuthorizationStatusCode());
        // 群成员
        List<CustomerGroupMember> groupMembers = groupWithRichMember.getGroupMembers();
        if (CollectionUtils.isEmpty(groupMembers)) {
            return resultSimpleGroupModel;
        }
        List<SimpleGroupMemberModel> memberModelList = new ArrayList<>();
        for (CustomerGroupMember groupMember : groupMembers) {
            SimpleGroupMemberModel memberModel = getSimpleGroupMemberModel(groupMember);
            memberModelList.add(memberModel);
        }
        resultSimpleGroupModel.setMemberModelList(memberModelList);
        return resultSimpleGroupModel;
    }

    private SimpleGroupMemberModel getSimpleGroupMemberModel(CustomerGroupMember groupMember) {
        if (Objects.isNull(groupMember)) {
            return null;
        }
        SimpleGroupMemberModel memberModel = new SimpleGroupMemberModel();
        memberModel.setMemberType(groupMember.getGroupMemberType().getCode());
        Employee employee = groupMember.getEmployee();
        if (GroupMemberTypeEnum.EMPLOYEE == groupMember.getGroupMemberType() && Objects.nonNull(employee)) {
            SimpleEmployeeModel employeeModel = getEmployeeModel(employee);
            memberModel.setEmployeeModel(employeeModel);
        }
        Customer customer = groupMember.getCustomer();
        if (GroupMemberTypeEnum.EXTERNAL_USER == groupMember.getGroupMemberType() && Objects.nonNull(customer)) {
            SimpleCustomerModel customerModel = getCustomerModel(customer);
            memberModel.setCustomerModel(customerModel);
        }
        memberModel.setJoinTime(groupMember.getJoinTime());
        if (Objects.nonNull(groupMember.getJoinScene())) {
            memberModel.setJoinScene(groupMember.getJoinScene().getCode());
        }
        return memberModel;
    }

    private SimpleCustomerModel getCustomerModel(Customer customer) {
        if (Objects.isNull(customer)) {
            return null;
        }
        SimpleCustomerModel customerModel = new SimpleCustomerModel();
        customerModel.setExternalUserId(customer.getExternalUserid());
        customerModel.setCustomerName(customer.getName());
        customerModel.setCustomerId(customer.getId());
        customerModel.setAvatar(customer.getAvatar());
        if (Objects.nonNull(customer.getStatus())) {
            customerModel.setCustomerStatus(customer.getStatus().getCode());
        }
        return customerModel;
    }

    private SimpleEmployeeModel getEmployeeModel(Employee employee) {
        if (Objects.isNull(employee)) {
            return null;
        }
        SimpleEmployeeModel owner = new SimpleEmployeeModel();
        owner.setUserId(employee.getTxUserId());
        owner.setUserName(employee.getName());
        owner.setAvatar(employee.getAvatar());
        owner.setOrgUserId(employee.getId());
        if (Objects.nonNull(employee.getStatus())) {
            owner.setEmployeeStatus(employee.getStatus().getCode());
        }
        if (Objects.nonNull(employee.getActiveStatus())) {
            owner.setActiveStatus(employee.getActiveStatus().getCode());
        }
        return owner;
    }


    /**
     * 统计群成员性别数量
     *
     * @param customerFutureList   customerFutureList
     * @param employeeFutureList   employeeFutureList
     * @param genderStatisticModel genderStatisticModel
     */
    private void getGenderStatisticModel(List<Future<List<Customer>>> customerFutureList, List<Future<List<Employee>>> employeeFutureList, GenderStatisticModel genderStatisticModel, List<CustomerGroupMember> memberList) {
        // 客户
        if (!CollectionUtils.isEmpty(customerFutureList)) {
            for (Future<List<Customer>> future : customerFutureList) {
                try {
                    List<Customer> customers = future.get(2L, TimeUnit.SECONDS);
                    if (CollectionUtils.isEmpty(customers)) {
                        continue;
                    }
                    Map<GenderEnum, Long> genderEnumLongMap = customers.stream().filter(e -> Objects.nonNull(e.getGender())).collect(Collectors.groupingBy(Customer::getGender, Collectors.counting()));
                    genderStatistic(genderEnumLongMap, genderStatisticModel);
                } catch (Exception e) {
                    log.error("getGenderStatisticModel,查询客户信息异常 error:", e);
                }
            }
        }

        // 员工
        if (!CollectionUtils.isEmpty(employeeFutureList)) {
            for (Future<List<Employee>> future : employeeFutureList) {
                try {
                    List<Employee> employees = future.get(2L, TimeUnit.SECONDS);
                    if (CollectionUtils.isEmpty(employees)) {
                        continue;
                    }
                    Map<GenderEnum, Long> genderEnumLongMap = employees.stream().filter(e -> Objects.nonNull(e.getGender())).collect(Collectors.groupingBy(Employee::getGender, Collectors.counting()));
                    genderStatistic(genderEnumLongMap, genderStatisticModel);
                } catch (Exception e) {
                    log.error("getGenderStatisticModel,查询员工信息异常 error:", e);
                }
            }
        }

        // 处理未查到的员工｜客户 按照位置处理
        int sum = genderStatisticModel.getSum();
        int memberSize = memberList.size();
        if (sum < memberSize) {
            genderStatisticModel.increaseUnknownNum(memberSize - sum);
        }
    }

    /**
     * 获取群信息携带 "充血" 群成员
     *
     * @param chatId 群ID
     * @return CustomerGroup
     */
    private CustomerGroup getGroupWithRichMember(String chatId, PrivateSphere privateSphere) {
        // 1、获取群信息携带 "贫血" 群成员
        CustomerGroup resultCustomerGroup = customerGroupExportServiceProxy.getGroupWithAnemicMember(privateSphere, chatId);
        if (Objects.isNull(resultCustomerGroup)) {
            return null;
        }
        List<CustomerGroupMember> groupMembers = resultCustomerGroup.getGroupMembers();

        if (CollectionUtils.isEmpty(groupMembers)) {
            return resultCustomerGroup;
        }

        // 2、异步分批获取员工&客户信息
        List<Future<List<Customer>>> customerFutureList = new ArrayList<>();
        List<Future<List<Employee>>> employeeFutureList = new ArrayList<>();
        fillFutureList(customerFutureList, employeeFutureList, privateSphere, groupMembers);

        // 3、充血群成员数据
        richGroupMemberModel(customerFutureList, employeeFutureList, groupMembers);
        return resultCustomerGroup;
    }

    /**
     * 异步分批获取员工&客户信息
     *
     * @param customerFutureList customerFutureList
     * @param employeeFutureList employeeFutureList
     * @param privateSphere      私域
     * @param memberList         memberList
     */
    private void fillFutureList(List<Future<List<Customer>>> customerFutureList, List<Future<List<Employee>>> employeeFutureList, PrivateSphere privateSphere, List<CustomerGroupMember> memberList) {
        // 按照成员类型分组
        Map<GroupMemberTypeEnum, List<CustomerGroupMember>> memberTypeListMap = memberList.stream().collect(Collectors.groupingBy(CustomerGroupMember::getGroupMemberType));

        // 客户
        List<CustomerGroupMember> customerMemberList = memberTypeListMap.get(GroupMemberTypeEnum.EXTERNAL_USER);
        if (!CollectionUtils.isEmpty(customerMemberList)) {
            List<String> externalUserIdList = customerMemberList.stream().map(CustomerGroupMember::getMemberId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<List<String>> partition = Customer.partitionExternalIds(new HashSet<>(externalUserIdList), partitionSize);
            for (List<String> list : partition) {
                Future<List<Customer>> future = customerGroupQueryThreadPool.submit(() -> {
                    // 查询客户
                    return customerServiceProxy.fetchCustomerByIds(null, list, privateSphere, false);
                });
                customerFutureList.add(future);
            }
        }

        // 员工
        List<CustomerGroupMember> employeeMemberList = memberTypeListMap.get(GroupMemberTypeEnum.EMPLOYEE);
        if (!CollectionUtils.isEmpty(employeeMemberList)) {
            List<String> employeeIdList = employeeMemberList.stream().map(CustomerGroupMember::getMemberId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<List<String>> partition = Lists.partition(employeeIdList, partitionSize);
            for (List<String> list : partition) {
                Future<List<Employee>> future = customerGroupQueryThreadPool.submit(() -> {
                    // 查询员工
                    MultiResponse<Employee> multiResponse = employeeProxy.getByEmployeeIdOrTxUserIds(privateSphere, list, null);
                    return multiResponse.getDataList();
                });
                employeeFutureList.add(future);
            }
        }
    }

    /**
     * 充血群成员数据
     *
     * @param customerFutureList      customerFutureList
     * @param employeeFutureList      employeeFutureList
     * @param customerGroupMemberList customerGroupMemberList
     */
    private void richGroupMemberModel(List<Future<List<Customer>>> customerFutureList, List<Future<List<Employee>>> employeeFutureList, List<CustomerGroupMember> customerGroupMemberList) {
        // 1、客户
        List<Customer> allCustomer = new ArrayList<>();
        Map<String, Customer> customerMap = new HashMap<>(16);
        if (CollectionUtils.isNotEmpty(customerFutureList)) {
            for (Future<List<Customer>> future : customerFutureList) {
                try {
                    List<Customer> customers = future.get(2L, TimeUnit.SECONDS);
                    if (CollectionUtils.isEmpty(customers)) {
                        continue;
                    }
                    allCustomer.addAll(customers);
                } catch (Exception e) {
                    log.error("richGroupMemberModel,查询客户信息异常 error:", e);
                }
            }
        }
        if (CollectionUtils.isNotEmpty(allCustomer)) {
            customerMap = allCustomer.stream().collect(Collectors.toMap(Customer::getExternalUserid, Function.identity(), (k1, k2) -> k1));
        }

        // 2、员工
        List<Employee> allEmployee = new ArrayList<>();
        Map<String, Employee> employeeMap = new HashMap<>(16);
        if (CollectionUtils.isNotEmpty(employeeFutureList)) {
            for (Future<List<Employee>> future : employeeFutureList) {
                try {
                    List<Employee> employees = future.get(2L, TimeUnit.SECONDS);
                    if (CollectionUtils.isEmpty(employees)) {
                        continue;
                    }
                    allEmployee.addAll(employees);
                } catch (Exception e) {
                    log.error("richGroupMemberModel,查询员工信息异常 error:", e);
                }
            }
        }
        if (CollectionUtils.isNotEmpty(allEmployee)) {
            employeeMap = allEmployee.stream().collect(Collectors.toMap(Employee::getId, Function.identity(), (k1, k2) -> k1));
        }
        // 3、充血群成员
        for (CustomerGroupMember customerGroupMember : customerGroupMemberList) {
            // 员工
            if (Objects.nonNull(customerGroupMember.getEmployee()) && Objects.nonNull(employeeMap.get(customerGroupMember.getEmployee().getId()))) {
                customerGroupMember.setEmployee(employeeMap.get(customerGroupMember.getEmployee().getId()));
            }
            // 客户
            if (Objects.nonNull(customerGroupMember.getCustomer()) && Objects.nonNull(customerMap.get(customerGroupMember.getCustomer().getExternalUserid()))) {
                customerGroupMember.setCustomer(customerMap.get(customerGroupMember.getCustomer().getExternalUserid()));
            }
        }
    }

    @Override
    public RetailStoreModifyBO batchModifyStore(RetailStoreModifyDTO dto) {
        // 判空
        List<String> chatIdList = dto.getChatIdList();
        if (CollectionUtils.isEmpty(chatIdList)) {
            return new RetailStoreModifyBO(false, "修改失败");
        }
        // 获取私域信息
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), false);

        // 判断勾选了解散的群
        CustomerGroup customerGroup = new CustomerGroup();
        customerGroup.setState(ChatGroupStateEnum.DISMISS);
        customerGroup.setPrivateSphere(privateSphere);
        MultiResponse<CustomerGroup> multiResponse = customerGroupExportServiceProxy.fetchCustomerGroupList(customerGroup, null, chatIdList, null, false, true, 1, 1, false);
        List<CustomerGroup> customerGroupList = multiResponse.getDataList();
        if (!CollectionUtils.isEmpty(customerGroupList)) {
            throw new BizException(BaseErrorCode.CHECK_DISSOLVE_GROUP_ERROR);
        }

        // 保存客户群门店关系
        List<CustomerGroupExternalRequest> externalList = new ArrayList<>();
        for (String chatId : chatIdList) {
            CustomerGroupExternalRequest customerGroupExternalRequest = new CustomerGroupExternalRequest();
            customerGroupExternalRequest.setCorpId(privateSphere.getCorpId());
            customerGroupExternalRequest.setPrivateSphere(privateSphere);
            customerGroupExternalRequest.setGroupId(chatId);
            customerGroupExternalRequest.setVid(dto.getRetailStoreId());
            customerGroupExternalRequest.setType(2);
            customerGroupExternalRequest.setDeleted(false);
            externalList.add(customerGroupExternalRequest);
        }
        customerGroupExportServiceProxy.saveAllCustomerGroupExternal(externalList);

        return new RetailStoreModifyBO(true, "修改成功");
    }

    @Override
    public RetailStoreModifyBO batchRelieveStore(RetailStoreModifyDTO dto) {
        // 判空
        List<String> chatIdList = dto.getChatIdList();
        if (CollectionUtils.isEmpty(chatIdList)) {
            return new RetailStoreModifyBO(true, "解除成功");
        }

        // 获取私域信息
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), false);

        // 判断勾选了解散的群
        CustomerGroup customerGroup = new CustomerGroup();
        customerGroup.setState(ChatGroupStateEnum.DISMISS);
        customerGroup.setPrivateSphere(privateSphere);
        MultiResponse<CustomerGroup> multiResponse = customerGroupExportServiceProxy.fetchCustomerGroupList(customerGroup, null, chatIdList, null, false, true, 1, 1, false);
        List<CustomerGroup> customerGroupList = multiResponse.getDataList();
        if (!CollectionUtils.isEmpty(customerGroupList)) {
            throw new BizException(BaseErrorCode.CHECK_DISSOLVE_GROUP_ERROR);
        }

        // 批量解除
        List<CustomerGroupExternalRequest> externalList = new ArrayList<>();
        for (String chatId : chatIdList) {
            CustomerGroupExternalRequest customerGroupExternalRequest = new CustomerGroupExternalRequest();
            customerGroupExternalRequest.setCorpId(privateSphere.getCorpId());
            customerGroupExternalRequest.setPrivateSphere(privateSphere);
            customerGroupExternalRequest.setGroupId(chatId);
            customerGroupExternalRequest.setVid("");
            customerGroupExternalRequest.setType(2);
            customerGroupExternalRequest.setDeleted(true);
            externalList.add(customerGroupExternalRequest);
        }
        customerGroupExportServiceProxy.saveAllCustomerGroupExternal(externalList);
        return new RetailStoreModifyBO(true, "解除成功");
    }

    @Override
    public List<GroupStatisticListBO> batchFetchGroupStatisticInfo(GroupStatisticQueryDTO dto) {
        // 校验
        if (Objects.isNull(dto) || CollectionUtils.isEmpty(dto.getGroupIdList())) {
            throw new BizException(BaseErrorCode.PARA_ERROR);
        }

        // 查私域
        PrivateSphere privateSphere = privateSphereThird.fetchByBosId(dto.getBosId());
        List<String> groupIdList = dto.getGroupIdList();

        // 群基础数
        CustomerGroup customerGroup = new CustomerGroup();
        customerGroup.setPrivateSphere(privateSphere);
        MultiResponse<CustomerGroup> multiResponse = customerGroupExportServiceProxy.fetchCustomerGroupList(customerGroup, null,
                groupIdList, null, false, false, null, null, false);
        List<CustomerGroup> groupList = multiResponse.getDataList();
        Map<String, CustomerGroup> groupMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(groupList)) {
            groupMap = groupList.stream().collect(Collectors.toMap(CustomerGroup::getGroupId, Function.identity(), (k1, k2) -> k1));
        }

        // 群统计数据
        Map<String, GroupStatisticModel> statisticModelMap = getStatisticModelMap(privateSphere, groupIdList, true);

        // 封装结果
        List<GroupStatisticListBO> resultList = new ArrayList<>();
        for (String groupId : groupIdList) {
            GroupStatisticListBO groupStatistic = new GroupStatisticListBO();
            covertGroupStatisticListBO(groupMap, statisticModelMap, groupId, groupStatistic);
            resultList.add(groupStatistic);
        }
        return resultList;
    }

    @Override
    public PageResponse<CorpChatGroupListBO> getGroupChatListByWid(CustomerChatGroupDTO customerChatGroupDTO) {
        // 1、查私域信息
        PrivateSphere privateSphere = privateSphereThird.fetch(customerChatGroupDTO.getBasicInfo(), false);
        // 2、wid查询externalUserId
        List<ExternalUserListBO> externalUserListBOS = customerFacade.getExternalUserInfoByWids(privateSphere,
                Lists.newArrayList(customerChatGroupDTO.getWid()), CustomerStatusEnum.DEFAULT.getCode(), false);
        if (CollectionUtils.isEmpty(externalUserListBOS)) {
            log.warn("getGroupChatListByWid externalUserListBOS is null,param:{}", customerChatGroupDTO.getWid());
            return null;
        }
        String externalUserId = externalUserListBOS.get(0).getExternalUserId();
        if (StringUtils.isBlank(externalUserId)) {
            log.error("getGroupChatListByWid externalUserId is null,param:{}", customerChatGroupDTO.getWid());
            return null;
        }
        Customer customer = new Customer();
        customer.setExternalUserid(externalUserId);
        // 3、查询最早入群时间
        MultiResponse<CustomerGroupMember> memberMultiResponse = customerGroupExportServiceProxy.fetchGroupMemberInfoByExternalUser(customer,
                privateSphere, customerChatGroupDTO.getPageNum(), customerChatGroupDTO.getPageSize());
        if (memberMultiResponse == null || CollectionUtils.isEmpty(memberMultiResponse.getDataList())) {
            return null;
        }
        PageResponse<CorpChatGroupListBO> pageResponse = new PageResponse<>();
        pageResponse.setTotalCount(memberMultiResponse.getTotalCount());

        List<CorpChatGroupListBO> chatGroupListBOList = new ArrayList<>();
        // 4 查询客户群信息
        getGroupInfoByExternalUserId(privateSphere, memberMultiResponse, chatGroupListBOList);
        pageResponse.setResults(chatGroupListBOList);
        return pageResponse;
    }

    private void getGroupInfoByExternalUserId(PrivateSphere privateSphere, MultiResponse<CustomerGroupMember> memberMultiResponse, List<CorpChatGroupListBO> chatGroupListBOList) {
        List<String> groupIds = new ArrayList<>();
        Map<String, CorpChatGroupListBO> groupListBOMap = new HashMap<>();
        for (CustomerGroupMember customerGroupMember : memberMultiResponse.getDataList()) {
            groupIds.add(customerGroupMember.getGroupId());

            CorpChatGroupListBO chatGroupListBO = new CorpChatGroupListBO();
            chatGroupListBO.setJoinTime(customerGroupMember.getJoinTime());
            chatGroupListBO.setChatId(customerGroupMember.getGroupId());
            chatGroupListBOList.add(chatGroupListBO);
            groupListBOMap.put(customerGroupMember.getGroupId(), chatGroupListBO);
        }

        CustomerGroup customerGroupRequest = new CustomerGroup();
        customerGroupRequest.setPrivateSphere(privateSphere);
        MultiResponse<CustomerGroup> groupMultiResponse = customerGroupExportServiceProxy.fetchCustomerGroupList(customerGroupRequest, null, groupIds, null, false, false, null, null, false);

        if (groupMultiResponse != null && CollectionUtils.isNotEmpty(groupMultiResponse.getDataList())) {
            for (CustomerGroup customerGroup : groupMultiResponse.getDataList()) {
                CorpChatGroupListBO chatGroupListBO = groupListBOMap.get(customerGroup.getGroupId());
                chatGroupListBO.setName(customerGroup.getName());
                chatGroupListBO.setOwnerName(customerGroup.getOwner() != null ? customerGroup.getOwner().getPersonUserName() : null);
                chatGroupListBO.setNum(customerGroup.getNum());
                chatGroupListBO.setGroupCreateTime(customerGroup.getGmtCreate());
                chatGroupListBO.setOwner(customerGroup.getOwner().getPersonUserId());
                chatGroupListBO.setOwnerAvatar(customerGroup.getOwner().getPersonUserAvatar());
                chatGroupListBO.setNotice(customerGroup.getNotice());
                chatGroupListBO.setExternalUserNum(customerGroup.getExternalUserNum());
                chatGroupListBO.setValidExternalUserNum(customerGroup.getValidExternalUserNum());
                chatGroupListBO.setGroupState(customerGroup.getState() != null ? customerGroup.getState().getCode().toString() : null);
                chatGroupListBO.setAuthorizationStatus(customerGroup.getAuthorizationStatusCode());
            }
        }
    }

    private void covertGroupStatisticListBO(Map<String, CustomerGroup> groupMap, Map<String, GroupStatisticModel> statisticModelMap, String groupId, GroupStatisticListBO groupStatistic) {
        if (MapUtils.isNotEmpty(groupMap) && Objects.nonNull(groupMap.get(groupId))) {
            CustomerGroup group = groupMap.get(groupId);
            groupStatistic.setAllNum(group.getNum());
            groupStatistic.setCustomerNum(group.getExternalUserNum());
        } else {
            groupStatistic.setAllNum(0);
            groupStatistic.setCustomerNum(0);
        }
        if (MapUtils.isNotEmpty(statisticModelMap) && Objects.nonNull(statisticModelMap.get(groupId))) {
            GroupStatisticModel model = statisticModelMap.get(groupId);
            groupStatistic.setJoinNum(model.getJoinNum());
            groupStatistic.setQuitNum(model.getQuitNum());
            groupStatistic.setNoFriendNum(model.getNoFriendNum());
        } else {
            groupStatistic.setJoinNum(0);
            groupStatistic.setQuitNum(0);
            groupStatistic.setNoFriendNum(0);
        }
    }

    @Override
    public PageResponse<CustomerChatGroupBO> getGroupChatListByMember(CustomerChatGroupDTO dto) {
        // 1、校验
        String externalUserId = dto.getExternalUserId();
        String employeeId = dto.getEmployeeId();
        String customerId = dto.getCustomerId();
        // 存在只有customerId的情况
        if (StringUtils.isBlank(customerId) && StringUtils.isBlank(externalUserId) && StringUtils.isBlank(employeeId)) {
            throw new BizException("群成员ID不能为空");
        }
        // 2、查私域
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), false);

        // 3、customerId 换 externalUserId
        if (StringUtils.isBlank(externalUserId) && StringUtils.isNotBlank(customerId)) {
            log.error("getGroupChatListByMember externalUserId 为空");
            externalUserId = getExternalUserId(customerId, privateSphere);
            if (StringUtils.isBlank(externalUserId)) {
                throw new BizException("根据customerId未查询到客户信息");
            }
            dto.setExternalUserId(externalUserId);
        }

        // 4、根据群成员查群
        MultiResponse<CustomerGroup> multiResponse = getGroupByMember(privateSphere, dto);
        List<CustomerGroup> customerGroupList = multiResponse.getDataList();
        if (CollectionUtils.isEmpty(customerGroupList)) {
            return new PageResponse<>(new ArrayList<>(), dto.getPageNum(), dto.getPageSize(), 0L);
        }
        // 5、查群成员
        Map<String, CustomerGroupMember> memberMap = new HashMap<>();
        if (Boolean.TRUE.equals(dto.getNeedFillMember())) {
            memberMap = getMemberMap(employeeId, externalUserId, privateSphere, customerGroupList);
        }
        // 6、模型转换
        List<CustomerChatGroupBO> customerChatGroupBOList = Lists.newArrayList();
        for (CustomerGroup customerGroup : customerGroupList) {
            CustomerChatGroupBO customerChatGroupBO = CustomerGroupConvert.getCustomerChatGroupBO(externalUserId, memberMap, customerGroup);
            customerChatGroupBOList.add(customerChatGroupBO);
        }
        // 7、响应结果
        return new PageResponse<>(customerChatGroupBOList, dto.getPageNum(), dto.getPageSize(), multiResponse.getTotalCount());
    }

    /**
     * 根据 customerId 换 externalUserId
     *
     * @param customerId
     * @return
     */
    private String getExternalUserId(String customerId, PrivateSphere privateSphere) {
        Customer customer = customerServiceProxy.fetchCustomer(customerId, null, privateSphere, ExternalUserTypeEnum.ALL);

        if (customer==null) {
            throw new BizException("客户不存在");
        }
        return customer.getExternalUserid();
    }

    /**
     * 根据 externalUserId 查群成员
     *
     * @param externalUserId
     * @param privateSphere
     * @param customerGroupList
     * @return map key:groupId value:群成员
     */
    private Map<String, CustomerGroupMember> getMemberMap(String employeeId, String externalUserId, PrivateSphere privateSphere, List<CustomerGroup> customerGroupList) {
        List<String> groupIdList = customerGroupList.stream().map(CustomerGroup::getGroupId).collect(Collectors.toList());
        CustomerGroupMember customerGroupMember = new CustomerGroupMember();
        customerGroupMember.setPrivateSphere(privateSphere);
        if (StringUtils.isNotBlank(employeeId)) {
            customerGroupMember.setGroupMemberType(GroupMemberTypeEnum.EMPLOYEE);
            Employee employee = new Employee();
            employee.setId(employeeId);
            customerGroupMember.setEmployee(employee);
        } else {
            customerGroupMember.setGroupMemberType(GroupMemberTypeEnum.EXTERNAL_USER);
            Customer customer = new Customer();
            customer.setExternalUserid(externalUserId);
            customerGroupMember.setCustomer(customer);
        }
        Map<String, Object> extInfo = new HashMap<>();
        extInfo.put(CustomerGroupConstant.GROUP_ID_LIST, groupIdList);
        extInfo.put(CustomerGroupConstant.FETCH_GUIDER,Boolean.TRUE);
        MultiResponse<CustomerGroupMember> memberMultiResponse = customerGroupExportServiceProxy.fetchCustomerGroupMemberList(customerGroupMember, extInfo, false, false, null, null);
        List<CustomerGroupMember> customerGroupMemberList = memberMultiResponse.getDataList();
        if (CollectionUtils.isEmpty(customerGroupMemberList)) {
            return new HashMap<>();
        }
        return customerGroupMemberList.stream().collect(Collectors.toMap(CustomerGroupMember::getGroupId, Function.identity(), (k1, k2) -> k1));
    }

    /**
     * 根据群成员查群列表
     *
     * @param privateSphere
     * @param dto
     * @return
     */
    private MultiResponse<CustomerGroup> getGroupByMember(PrivateSphere privateSphere, CustomerChatGroupDTO dto) {
        CustomerGroupMember customerGroupMember = new CustomerGroupMember();
        if (StringUtils.isNotBlank(dto.getExternalUserId())) {
            customerGroupMember.setGroupMemberType(GroupMemberTypeEnum.EXTERNAL_USER);
            Customer customer = new Customer();
            customer.setExternalUserid(dto.getExternalUserId());
            customerGroupMember.setCustomer(customer);
        }
        if (StringUtils.isNotBlank(dto.getEmployeeId())) {
            customerGroupMember.setGroupMemberType(GroupMemberTypeEnum.EMPLOYEE);
            Employee employee = new Employee();
            employee.setId(dto.getEmployeeId());
            customerGroupMember.setEmployee(employee);
        }
        if (StringUtils.isNotBlank(dto.getGroupName())) {
            CustomerGroup customerGroup = new CustomerGroup();
            customerGroup.setName(dto.getGroupName());
            customerGroupMember.setCustomerGroup(customerGroup);
        }
        boolean needPage = false;
        if (Objects.nonNull(dto.getPageNum()) && Objects.nonNull(dto.getPageSize())) {
            needPage = true;
        }
        HashMap<String, Object> extInfo = new HashMap<>(16);
        extInfo.put(CustomerGroupConstant.AUTHORIZATION_STATUS, GroupAuthorizationStatusEnum.AUTHORIZED.getCode());
        return customerGroupExportServiceProxy.fetchCustomerGroupListByMember(privateSphere, customerGroupMember, extInfo, false, needPage, dto.getPageNum(), dto.getPageSize());
    }

    private List<RetailStoreExcelDTO> getRetailStoreExcelDTOS(String excelUrl) {

        //首先下载 & 解析Excel
        List<RetailStoreExcelDTO> retailStoreExcelDTOS;
        try {
            InputStream downloadFileResponse = picServerProxy.download(excelUrl);
            ExcelTypeEnum excelTypeEnum = EasyExcelUtils.getExcelTypeEnum(excelUrl);
            retailStoreExcelDTOS = (List<RetailStoreExcelDTO>) EasyExcelUtils.readExcel(downloadFileResponse, excelTypeEnum, RetailStoreExcelDTO.class, 1, 1);
        } catch (Exception e) {
            log.info("ChatGroupImpl excel2Dto url:{}, error:{}", excelUrl, e);
            throw new BizException(BaseErrorCode.EXCEL_ERROR);
        }

        if (retailStoreExcelDTOS.isEmpty()) {
            //没有数据,不做处理
            //throw new BizException(BaseErrorCode.EXCEL_EMPTY);
        }

        // 保留前1000条数据，超过部分舍去
        if (retailStoreExcelDTOS.size() > 1000) {
            retailStoreExcelDTOS = retailStoreExcelDTOS.subList(0, 1000);
        }
        return retailStoreExcelDTOS;
    }

    private UploadRes uploadExcel(List<RetailStoreExcelDTO> checkFailExcelDTOS) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
        String fileName = "企微客群关联门店配置-错误原因" + sdf.format(new Date()) + ".xlsx";

        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            EasyExcelFactory.write(outputStream, RetailStoreExcelDTO.class).
                    sheet("数据").doWrite(checkFailExcelDTOS);
            //上传并获取媒体中心返回的对象
            return picServerProxy.getUploadRes(new ByteArrayInputStream(outputStream.toByteArray()), fileName);
        } catch (Exception e) {
            log.error("PotentialCustomerServiceImpl uploadExcel cause by:{}", e.getMessage(), e);
        }
        throw new BizException(BaseErrorCode.FAILED);
    }

    private void batchInsertGroupStoreRelate(List<RetailStoreExcelDTO> retailStoreExcelDTOList, Map<String, List<CustomerGroup>> groupMap, Map<String, NodeInfoQueryBO> storeSimpleInfoVoMap ,PrivateSphere privateSphere) {
        List<CustomerGroupExternalRequest> externalList = new ArrayList<>();
        for (RetailStoreExcelDTO retailStoreExcelDTO : retailStoreExcelDTOList) {
            List<CustomerGroup> groupList = groupMap.get(retailStoreExcelDTO.getChatName());
            for (CustomerGroup group : groupList) {
                CustomerGroupExternalRequest relate = new CustomerGroupExternalRequest();
                relate.setCorpId(group.getCorpId());
                relate.setPrivateSphere(privateSphere);
                relate.setGroupId(group.getGroupId());
                relate.setVid(storeSimpleInfoVoMap.get(retailStoreExcelDTO.getRetailStoreName()).getNodeInfo().getVidCode());
                relate.setType(2);
                relate.setDeleted(false);
                externalList.add(relate);
            }
        }
        customerGroupExportServiceProxy.saveAllCustomerGroupExternal(externalList);
    }

    /**
     * 查询带部门层级关系的员工信息
     *
     * @param privateSphere
     * @param generalIdList
     * @return
     */
    private Map<String, EmployeeBO> getStringEmployeeBOMap(PrivateSphere privateSphere, List<String> generalIdList) {
        Map<String, EmployeeBO> employeeIdEmployeeMap = new HashMap<>();
        if (CollectionUtils.isEmpty(generalIdList)) {
            return employeeIdEmployeeMap;
        }
        EmployeeDTO employeeDTO = new EmployeeDTO();
        employeeDTO.setCorpId(privateSphere.getCorpId());
        employeeDTO.setPrivateSphereId(privateSphere.getPrivateSphereId());
        employeeDTO.setBosId(privateSphere.getBosId());
        employeeDTO.setIds(generalIdList);
        employeeDTO.setFetchGuider(true);
        employeeDTO.setExceptDeleted(true);
        employeeDTO.setFetchParentDepartment(true);
        List<EmployeeBO> orgUserList = SoaUtil.unpack(orgDepartmentUserExport.getUsersByIds(employeeDTO));
        employeeIdEmployeeMap = CollUtils.toMap(orgUserList, EmployeeBO::getOrgUserId, Function.identity());
        return employeeIdEmployeeMap;
    }

    /**
     * 拼接所有的部门名称
     *
     * @param departments
     * @return
     */
    private List<String> jointDepartmentName(List<List<OrgDepartmentBO>> departments) {
        if (CollectionUtils.isEmpty(departments)) {
            return Collections.emptyList();
        }
        List<String> departmentNames = Lists.newLinkedList();
        for (List<OrgDepartmentBO> orgDepartments : departments) {
            if (CollectionUtils.isEmpty(orgDepartments)) {
                continue;
            }
            StringBuilder departName = new StringBuilder();
            // 按照level升序
            List<OrgDepartmentBO> filterOrgDepartments = orgDepartments.stream().filter(item -> item.getLevel() != null).sorted(Comparator.comparingInt(OrgDepartmentBO::getLevel)).collect(Collectors.toList());
            for (OrgDepartmentBO orgDepartment : filterOrgDepartments) {
                departName.append(orgDepartment.getName()).append("/");
            }
            if (StringUtils.isNotBlank(departName)) {
                departmentNames.add(StringUtils.substring(departName.toString(), 0, departName.length() - 1));
            }
        }
        return departmentNames;
    }

    /**
     * 统计性别数量
     *
     * @param genderEnumLongMap    genderEnumLongMap
     * @param genderStatisticModel genderStatisticModel
     */
    private void genderStatistic(Map<GenderEnum, Long> genderEnumLongMap, GenderStatisticModel genderStatisticModel) {
        genderEnumLongMap.forEach((key, val) -> {
                    if (GenderEnum.MALE.equals(key)) {
                        genderStatisticModel.increaseMaleNum(val.intValue());
                    } else if (GenderEnum.FEMALE.equals(key)) {
                        genderStatisticModel.increaseFemaleNum(val.intValue());
                    } else {
                        genderStatisticModel.increaseUnknownNum(val.intValue());
                    }
                }
        );
    }

}
